import pandas as pd
import numpy as np
import os

# 导入模块
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics

from sklearn import pipeline  # 管道，通过管道构建 多项式线性模型
from sklearn.preprocessing import PolynomialFeatures  # 多项式特征

from sklearn.neighbors import KNeighborsClassifier

"""
**机器学习实现流程：**
1. 构造数据
2. 构建模型
3. 模型训练
4. 模型测试
5. 模型评估
6. 模型应用
"""


class MachineLearn(object):
    """机器学习类"""

    def __init__(self):
        """初始化数据
               iris数据集介绍
               150个数据， 分为三类  每类都是50个数据
               每个数据包含：
               四种属性：花萼长度 ， 花萼宽度 ， 花瓣长度， 花瓣宽度
               三个类别： 山鸢尾，杂色鸢尾，维吉尼亚鸢尾花
               sepal width:花萼宽度 单位cm
               sepal length:花萼长度 单位cm
               petal width:花瓣宽度 单位cm
               petal length:花瓣长度 单位cm
               Iris-setosa : 山鸢尾花
               Iris-versicolor：杂色鸢尾花
               Iris-virginica 维吉尼亚鸢尾花
               """
        # 准备数据
        self.PATH = os.path.abspath(os.path.dirname(__file__)) + os.sep
        FILE_PATH = self.PATH + "data" + os.sep + "iris.data"
        data = pd.read_csv(FILE_PATH, names=["sepal_length", "sepal_width", "petal_length", "petal_width", "class"])
        # print(data.head())

        # 1. 构造数据
        # todo 线性回归数据集 ： 花瓣宽度与花瓣长度关系 进行线性拟合
        reg_x = data.loc[:, "petal_width"]  # 第一个参数 ： 行， 第二个参数是列 ,取 所有花瓣的宽度值
        # 把二维转为一维
        reg_x = np.array(reg_x).reshape(-1, 1)
        # print(reg_x)
        reg_y = data.loc[:, "petal_length"]  # 取所有花瓣的长度值
        # 训练集与测试集切分
        self.reg_x_train, self.reg_x_test, self.reg_y_train, self.reg_y_test = \
            train_test_split(reg_x, reg_y, test_size=0.2, random_state=8)
        # random_state 随机种子
        # print(self.reg_x_test)

        # todo 分类数据集的构建
        type_x = data.iloc[:, :-1]  # 取得特征数据集
        type_y = data.iloc[:, -1]  # 取得目标(标记)数据集
        # print(type_x.head())

        # 分类预测 训练集和测试集切分
        self.type_x_train, self.type_x_test, self.type_y_train, self.type_y_test = \
            train_test_split(type_x, type_y, test_size=0.2, random_state=6)

        # print(self.type_x_test)

    def linearRegression(self, petal_width):  # reg_x = np.array(reg_x).reshape(-1, 1) 把二维转为一维
        """线性回归模型"""
        # 2.构建模型
        model = LinearRegression()
        # 3.模型训练
        model.fit(self.reg_x_train, self.reg_y_train)
        # 4. 模型预测
        pred_y = model.predict(self.reg_x_test)
        # 5.模型评估
        score = round(metrics.r2_score(self.reg_y_test, pred_y), 2)
        # 6.模型应用
        pred = round(model.predict(np.array(petal_width).reshape(-1, 1))[0], 2)
        # print(f"预测结果:{pred} 线性回归模型R方得分:{score}")
        result = f"预测结果:{pred} 线性回归模型R方得分:{score}"
        return result

    def polyRegresson(self, petal_width):
        """多项式线性回归模型"""
        # 2.构建模型
        model = pipeline.make_pipeline(PolynomialFeatures(5), LinearRegression())  # 5代表最高幂次为5的多项式回归
        # 3.模型训练
        model.fit(self.reg_x_train, self.reg_y_train)
        # 4. 模型预测
        pred_y = model.predict(self.reg_x_test)
        # 5.模型评估
        score = round(metrics.r2_score(self.reg_y_test, pred_y), 2)
        # 6.模型应用
        pred = round(model.predict(np.array(petal_width).reshape(-1, 1))[0], 2)
        # print(f"预测结果:{pred} 线性回归模型R方得分:{score}")
        result = f"预测结果:{pred} 多项式回归模型R方得分:{score}"
        print(result)
        return result

    def knn(self, pred=[[1, 1, 1, 1]]):
        """KNN近邻模型"""
        # 2.构建模型
        model = KNeighborsClassifier(n_neighbors=3)  # 参考的邻居为3
        # 3.模型训练
        model.fit(self.type_x_train, self.type_y_train)
        # 4. 模型预测
        type_pred_y = model.predict(self.type_x_test)
        # 5.模型评估
        score = round(metrics.accuracy_score(self.type_y_test, type_pred_y), 2)
        # 6.模型应用
        type_pred = model.predict(pred)[0]
        result=f"精确度:{score} 预测类型：{type_pred}"

        return type_pred,score


if __name__ == '__main__':
    ml = MachineLearn()
    # ml.linearRegression(3)
    # ml.polyRegresson(3)
    ml.knn()
